use crate::excels::utils::capitalize_first_letter;

use super::{
    datas::ColumnData,
    utils::{
        ARR_BYTE, ARR_FLOAT, ARR_INT, ARR_NUMBER, ARR_SHORT, ARR_STRING, ARR_UINT, ARR_U_BYTE,
        ARR_U_SHORT, BYTE, FLOAT, INT, NUMBER, SHORT, STRING, UINT, U_BYTE, U_SHORT,
    },
};

///代码生成器
pub trait CodeGenerater: Send + Sync {
    fn generate_enum_head(&self) -> String;
    fn generate_enum(&self, file_name: &str, sheet_name: &str) -> String;
    ///生成代码头
    fn generate_head(&self, space_name: &str) -> String;
    fn generate_end(&self) -> String;
    fn generate(
        &self,
        sheet_name: &str,
        datas: &Vec<ColumnData>
    ) -> String;
}

pub struct TsCodeGenerater {}

impl Clone for TsCodeGenerater {
    fn clone(&self) -> Self {
        TsCodeGenerater {}
    }
}

impl CodeGenerater for TsCodeGenerater {
    fn generate_enum_head(&self) -> String {
        String::from("export enum ConfigKeys {\n")
    }

    fn generate_enum(&self, file_name: &str, sheet_name: &str) -> String {
        let file = capitalize_first_letter(file_name);
        let sheet = capitalize_first_letter(sheet_name);
        format!(
            "   {}_{} = \"{}/{}\",\n",
            file, sheet, file_name, sheet_name
        )
    }

    fn generate_head(&self, space_name: &str) -> String {
        let space_name = capitalize_first_letter(space_name);
        format!("declare namespace {} {{\n", space_name)
    }

    fn generate_end(&self) -> String {
        String::from("}\n")
    }

    fn generate(&self, sheet_name: &str, datas: &Vec<ColumnData>) -> String {
        let sheet_name = capitalize_first_letter(sheet_name);
        let mut result = format!("   export interface {} {{\n", sheet_name);

        let titles = datas
            .iter()
            .map(|i| i.title.clone())
            .collect::<Vec<String>>();

        let types = datas.iter().map(|i| i.true_type).collect::<Vec<u8>>();
        let comments = datas
            .iter()
            .map(|i| i.comment.clone())
            .collect::<Vec<String>>();

        for i in 0..titles.len() {
            let mut line: String = String::new();
            let title = titles.get(i).unwrap();
            let type_u8 = types.get(i).unwrap();
            let mut comment = String::new();
            if let Some(c) = comments.get(i) {
                comment.push_str(c);
            } else {
                comment.push_str(title);
            }
            if !comment.is_empty() {
                line.push_str(&format!("      /** {} */\n", comment));
            }
            match *type_u8 {
                STRING => line.push_str(&format!("      {}: string;\n", title)),
                BYTE | U_BYTE | SHORT | U_SHORT | INT | UINT | FLOAT | NUMBER => {
                    line.push_str(&format!("      {}: number;\n", title))
                }
                ARR_BYTE | ARR_U_BYTE | ARR_SHORT | ARR_U_SHORT | ARR_INT | ARR_UINT
                | ARR_FLOAT | ARR_NUMBER => {
                    line.push_str(&format!("      {}: Array<number>;\n", title));
                }
                ARR_STRING => {
                    line.push_str(&format!("      {}: Array<string>;\n", title));
                }
                _ => {
                    panic!("暂不支持该类型！")
                }
            }
            if line.is_empty() {
                continue;
            }
            result.push_str(&line);
        }
        result.push_str("   }\n");
        result
    }
}
